Step 0: check and install needed packages. Load the libraries and functions.

# packages.used=c("rvest", "tibble", "qdap", 
#                 "sentimentr", "gplots", "dplyr",
#                 "tm", "syuzhet", "factoextra", 
#                 "beeswarm", "scales", "RColorBrewer",
#                 "RANN", "tm", "topicmodels")
# 
# # check packages that need to be installed.
# packages.needed=setdiff(packages.used, 
#                         intersect(installed.packages()[,1], 
#                                   packages.used))
# # install additional packages
# if(length(packages.needed)>0){
#   install.packages(packages.needed, dependencies = TRUE)
# }
# load packages
library("rvest")
library("tibble")
# You may need to run
#system("ln -f -s $(/usr/libexec/java_home)/jre/lib/server/libjvm.dylib /usr/local/lib")
# sudo ln -f -s $(/usr/libexec/java_home)/jre/lib/server/libjvm.dylib /usr/local/lib
# in order to load qdap
library("qdap")
library("sentimentr")
library("gplots")
library("dplyr")
library("tm")
library("syuzhet")
library("factoextra")
library("beeswarm")
library("scales")
library("RColorBrewer")
library("RANN")
library("tm")
library("topicmodels")
library(wordcloud)
library(RColorBrewer)
library(tidytext)
library("xlsx")
library("ggplot2")
source("./lib/plotstacked.R")
source("./lib/speechFuncs.R")

This notebook was prepared with the following environmental settings.

print(R.version)

Step 1: Data harvest:

First import all data needed: InauguationDates.txt, InaugurationInfo.xlsx and all speeches text.

inaug.dates <- read.table("./data/InauguationDates.txt",header=TRUE,sep="\t")
inaug.info <- read.xlsx("./data/InaugurationInfo.xlsx",sheetName="Sheet1",header=T,stringsAsFactors = FALSE)
inaug.info$Words <- as.numeric(inaug.info$Words)
filenames = list.files("./data/InauguralSpeeches") #get all file name
dir = paste("./data/InauguralSpeeches/",filenames,sep="")
n = length(dir)
speeches = list()
for (i in 1:n){
  filename = paste("./data/InauguralSpeeches/inaug",inaug.info$File[i],"-",inaug.info$Term[i],".txt",sep="")
  new.data = paste(readLines(filename, n=-1, skipNul=TRUE),collapse=" ")
  speeches = c(speeches,new.data)
}
names(speeches) <- paste(inaug.info$File, inaug.info$Term,sep="-")

Step 2: data Processing — generate list of sentences

Use “?”, “.”, “!”, “|”,“;” as stop point of one sentence and extract all sentences from speeches.

sentence.list=NULL
for(i in 1:58){
  sentences=sent_detect(speeches[i],
                        endmarks = c("?", ".", "!", "|",";"))
  if(length(sentences)>0){
    emotions=get_nrc_sentiment(sentences)
    word.count=word_count(sentences)
    emotions=diag(1/(word.count+0.01))%*%as.matrix(emotions)
    sentence.list=rbind(sentence.list, 
                        cbind(inaug.info[i,-ncol(inaug.info)],
                              sentences=as.character(sentences), 
                              word.count,
                              emotions,
                              sent.id=1:length(sentences)
                              )
    )
  }
}

Delete all non-sentences resulted by erroneous extra end-of-sentence marks.

sentence.list=
  sentence.list%>%
  filter(!is.na(word.count)) 

Step 3: Data analysis

3.1. total number of words

Before we analyze length of single sentences, let’s have an prewview of total number of words in a speech. Draw a plot of length of speech against their time order.

ggplot(inaug.info) +
  geom_point(aes(1:58,Words)) +
  geom_smooth(aes(1:58,Words))

Notice that as time went by, the total number of words in a speech tend to be less and converges to around 2000. As we know, shorter speech leads to shorter time scale. We can draftly conclude that the speeches tend to be more concise. The speakers knew that the longer their speech is, the less interest people have to hear their words. But too less words can not precisely convey their political thoughts. Therefore, the number of words in a speech have the tendency to be within some certain range.

3.2. length of sentences

Now we want to find something about the length of sentences.

As we can see on above plot, y-coordinate follows the time order. GeorgeWashington is the first president while DonaldJTrump is the present president. We found that as time went by, the number of words in a sentence becomes less and less. The presidents tend to use less words in a sentence.

What are these short sentences?

sentence.list%>%
  filter(File=="GeorgeWashington", 
         word.count<=10&word.count>1)%>%
  select(sentences)%>%sample_n(2)
sentence.list%>%
  filter(File=="ThomasJefferson", 
         word.count<=5&word.count>1)%>%
  select(sentences)%>%sample_n(5)
sentence.list%>%
  filter(File=="AbrahamLincoln", 
         word.count<=5&word.count>1)%>%
  select(sentences)%>%sample_n(4)
sentence.list%>%
  filter(File=="FranklinDRoosevelt", 
         word.count<=5&word.count>1)%>%
  select(sentences)%>%sample_n(5)
sentence.list%>%
  filter(File=="BarackObama", 
         word.count<=5&word.count>1)%>%
  select(sentences)%>%sample_n(5)
sentence.list%>%
  filter(File=="DonaldJTrump", 
         word.count<=5&word.count>1)%>%
  select(sentences)%>%sample_n(5)

Let’s select 6 very famous presidents among American history. Each of them represents different time period. George Washington represents the very beginning of American history while DonaldJ Trump stands for the lastest.

From the output above, George Washington used a sentence with less than 10 words only twice while DonaldJ Trump used a sentence with less than 5 words more than 5 times. George Washington and Thomas Jefferson talks more about freedom and the foundation of America. Abraham Lincoln and Franklin D. Roosevelt who were presidents during war period, their worsds fight for peace and encourage people during hard days. As for DonaldJ Trump and Barack Obama, who are presidents during peace period but suffered from economic crisis, their words focuses more on recovery of economy.

As pace of history pushes forward, the American people faced different problems during different period and their presidents focused on the most impressive topic for people’s life.

Step 3: Data analysis

3.2. sentiment analsis

Sentence length variation over the course of the speech, with emotions.

par(mfrow=c(6,1), mar=c(1,0,2,0), bty="n", xaxt="n", yaxt="n", font.main=1)
f.plotsent.len(In.list=sentence.list, InFile="GeorgeWashington", 
               President="George Washington")
f.plotsent.len(In.list=sentence.list, InFile="ThomasJefferson", 
               President="Thomas Jefferson")
f.plotsent.len(In.list=sentence.list, InFile="AbrahamLincoln", 
               President="Abraham Lincoln")
f.plotsent.len(In.list=sentence.list, InFile="FranklinDRoosevelt", 
               President="Franklin D. Roosevelt")
f.plotsent.len(In.list=sentence.list, InFile="BarackObama", 
               President="Barack Obama")
f.plotsent.len(In.list=sentence.list, InFile="DonaldJTrump", 
               President="Donald Trump")

We can see that the older presidents(George Washington and Thomas Jefferson) tend to use long sentences to express their opinions precisely. While the newer presidents(Barac kObama and Donald Trump) tend to use short sentences to encourage people and convey their feelings to get emotional resonance.

What are the emotionally charged sentences?

print("George Washington")
[1] "George Washington"
speech.df=tbl_df(sentence.list)%>%
  filter(File=="GeorgeWashington", word.count>=4)%>%
  select(sentences, anger:trust)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
[1] "Previous to the execution of any official act of the President the Constitution requires an oath of office."                                                                                                                                                         
[2] "and since the preservation of the sacred fire of liberty and the destiny of the republican model of government are justly considered, perhaps, as deeply, as finally, staked on the experiment entrusted to the hands of the American people."                       
[3] "between the genuine maxims of an honest and magnanimous policy and the solid rewards of public prosperity and felicity;"                                                                                                                                             
[4] "Previous to the execution of any official act of the President the Constitution requires an oath of office."                                                                                                                                                         
[5] "I dwell on this prospect with every satisfaction which an ardent love for my country can inspire, since there is no truth more thoroughly established than that there exists in the economy and course of nature an indissoluble union between virtue and happiness;"
[6] "From this resolution I have in no instance departed;"                                                                                                                                                                                                                
[7] "Having thus imparted to you my sentiments as they have been awakened by the occasion which brings us together, I shall take my present leave;"                                                                                                                       
[8] "Previous to the execution of any official act of the President the Constitution requires an oath of office."                                                                                                                                                         
print("Thomas Jefferson")
[1] "Thomas Jefferson"
speech.df=tbl_df(sentence.list)%>%
  filter(File=="ThomasJefferson", word.count>=5)%>%
  select(sentences, anger:trust)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
[1] "the supremacy of the civil over the military authority;"                                 
[2] "The experiment has been tried;"                                                          
[3] "they saw the latent source from which these outrages proceeded;"                         
[4] "the supremacy of the civil over the military authority;"                                 
[5] "peace, commerce, and honest friendship with all nations, entangling alliances with none;"
[6] "peace, commerce, and honest friendship with all nations, entangling alliances with none;"
[7] "The experiment has been tried;"                                                          
[8] "peace, commerce, and honest friendship with all nations, entangling alliances with none;"
print("Abraham Lincoln")
[1] "Abraham Lincoln"
speech.df=tbl_df(sentence.list)%>%
  filter(File=="AbrahamLincoln", word.count>=4)%>%
  select(sentences, anger:trust)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
[1] "Whoever rejects it does of necessity fly to anarchy or to despotism."                            
[2] "Each looked for an easier triumph, and a result less fundamental and astounding."                
[3] "'May' Congress prohibit slavery in the Territories?"                                             
[4] "The Government will not assail 'you'."                                                           
[5] "Fondly do we hope, fervently do we pray, that this mighty scourge of war may speedily pass away."
[6] "Whoever rejects it does of necessity fly to anarchy or to despotism."                            
[7] "The Government will not assail 'you'."                                                           
[8] "Perpetuity is implied, if not expressed, in the fundamental law of all national governments."    
print("Franklin D. Roosevelt")
[1] "Franklin D. Roosevelt"
speech.df=tbl_df(sentence.list)%>%
  filter(File=="FranklinDRoosevelt", word.count>=4)%>%
  select(sentences, anger:trust)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
[1] "Happiness lies not in the mere possession of money;"  "We shall strive for perfection."                     
[3] "Yet our distress comes from no failure of substance." "These are the lines of attack."                      
[5] "Have we found our happy valley?"                      "We are stricken by no plague of locusts."            
[7] "power to do good."                                    "Have we found our happy valley?"                     
print("Barack Obama")
[1] "Barack Obama"
speech.df=tbl_df(sentence.list)%>%
  filter(File=="BarackObama", word.count>=4)%>%
  select(sentences, anger:trust)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
[1] "The Capital was abandoned."                                                  
[2] "This is the journey we continue today."                                      
[3] "Our capacity remains undiminished."                                          
[4] "Our capacity remains undiminished."                                          
[5] "when the wages of honest labor liberate families from the brink of hardship."
[6] "The Capital was abandoned."                                                  
[7] "when the wages of honest labor liberate families from the brink of hardship."
[8] "We affirm the promise of our democracy."                                     
print("Donald Trump")
[1] "Donald Trump"
speech.df=tbl_df(sentence.list)%>%
  filter(File=="DonaldJTrump", word.count>=5)%>%
  select(sentences, anger:trust)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
[1] "There should be no fear."                                                                           
[2] "America will start winning again, winning like never before."                                       
[3] "America will start winning again, winning like never before."                                       
[4] "There should be no fear."                                                                           
[5] "buy American and hire American."                                                                    
[6] "America will start winning again, winning like never before."                                       
[7] "The bible tells us how good and pleasant it is when God's people live together in unity."           
[8] "At the center of this movement is a crucial conviction, that a nation exists to serve its citizens."

Clustering of emotions

par(mar=c(4, 6, 2, 1))
emo.means=colMeans(select(sentence.list, anger:trust)>0.01)
col.use=c("red2", "darkgoldenrod1", 
            "chartreuse3", "blueviolet",
            "darkgoldenrod2", "dodgerblue3", 
            "darkgoldenrod1", "darkgoldenrod1")
barplot(emo.means[order(emo.means)], las=2, col=col.use[order(emo.means)], horiz=T, main="Inaugural Speeches")

We can find that a president must convey positive feelings like trust in order to get people’s trust.

presid.summary=tbl_df(sentence.list)%>%
  filter(File%in%sel.comparison)%>%
  group_by(File)%>%
  summarise(
    anger=mean(anger),
    anticipation=mean(anticipation),
    disgust=mean(disgust),
    fear=mean(fear),
    joy=mean(joy),
    sadness=mean(sadness),
    surprise=mean(surprise),
    trust=mean(trust)
    #negative=mean(negative),
    #positive=mean(positive)
  )
presid.summary=as.data.frame(presid.summary)
rownames(presid.summary)=as.character((presid.summary[,1]))
km.res=kmeans(presid.summary[,-1], iter.max=200,
              5)
fviz_cluster(km.res, 
             stand=F, repel= TRUE,
             data = presid.summary[,-1], xlab="", xaxt="n",
             show.clust.cent=FALSE)

presid.tmp=tbl_df(sentence.list[inaug.info$Party=="Democratic",])%>%
  group_by(File)%>%
  summarise(
    anger=mean(anger),
    anticipation=mean(anticipation),
    disgust=mean(disgust),
    fear=mean(fear),
    joy=mean(joy),
    sadness=mean(sadness),
    surprise=mean(surprise),
    trust=mean(trust)
  )
inaug.info$Party
 [1] "NA"                          "NA"                          "Fedralist"                  
 [4] "Democratic-Republican Party" "Democratic-Republican Party" "Democratic-Republican Party"
 [7] "Democratic-Republican Party" "Democratic-Republican Party" "Democratic-Republican Party"
[10] "Democratic-Republican Party" "Democratic"                  "Democratic"                 
[13] "Democratic"                  "Whig"                        "Democratic"                 
[16] "Whig"                        "Democratic"                  "Democratic"                 
[19] "Republican"                  "Republican"                  "Republican"                 
[22] "Republican"                  "Republican"                  "Republican"                 
[25] "Democratic"                  "Republican"                  "Democratic"                 
[28] "Republican"                  "Republican"                  "Republican"                 
[31] "Republican"                  "Democratic"                  "Democratic"                 
[34] "Republican"                  "Republican"                  "Republican"                 
[37] "Democratic"                  "Democratic"                  "Democratic"                 
[40] "Democratic"                  "Democratic"                  "Republican"                 
[43] "Republican"                  "Democratic"                  "Democratic"                 
[46] "Republican"                  "Republican"                  "Democratic"                 
[49] "Republican"                  "Republican"                  "Republican"                 
[52] "Democratic"                  "Democratic"                  "Republican"                 
[55] "Republican"                  "Democratic"                  "Democratic"                 
[58] "Republican"                 
presid.summary=as.data.frame(presid.summary)
rownames(presid.summary)=as.character((presid.summary[,1]))
km.res=kmeans(presid.summary[,-1], iter.max=200,
              5)
fviz_cluster(km.res, 
             stand=F, repel= TRUE,
             data = presid.summary[,-1], xlab="", xaxt="n",
             show.clust.cent=FALSE)

presid.tmp=tbl_df(sentence.list[inaug.info$Party=="Republican",])%>%
  group_by(File)%>%
  summarise(
    anger=mean(anger),
    anticipation=mean(anticipation),
    disgust=mean(disgust),
    fear=mean(fear),
    joy=mean(joy),
    sadness=mean(sadness),
    surprise=mean(surprise),
    trust=mean(trust)
  )
inaug.info$Party
 [1] "NA"                          "NA"                          "Fedralist"                  
 [4] "Democratic-Republican Party" "Democratic-Republican Party" "Democratic-Republican Party"
 [7] "Democratic-Republican Party" "Democratic-Republican Party" "Democratic-Republican Party"
[10] "Democratic-Republican Party" "Democratic"                  "Democratic"                 
[13] "Democratic"                  "Whig"                        "Democratic"                 
[16] "Whig"                        "Democratic"                  "Democratic"                 
[19] "Republican"                  "Republican"                  "Republican"                 
[22] "Republican"                  "Republican"                  "Republican"                 
[25] "Democratic"                  "Republican"                  "Democratic"                 
[28] "Republican"                  "Republican"                  "Republican"                 
[31] "Republican"                  "Democratic"                  "Democratic"                 
[34] "Republican"                  "Republican"                  "Republican"                 
[37] "Democratic"                  "Democratic"                  "Democratic"                 
[40] "Democratic"                  "Democratic"                  "Republican"                 
[43] "Republican"                  "Democratic"                  "Democratic"                 
[46] "Republican"                  "Republican"                  "Democratic"                 
[49] "Republican"                  "Republican"                  "Republican"                 
[52] "Democratic"                  "Democratic"                  "Republican"                 
[55] "Republican"                  "Democratic"                  "Democratic"                 
[58] "Republican"                 
presid.summary=as.data.frame(presid.summary)
rownames(presid.summary)=as.character((presid.summary[,1]))
km.res=kmeans(presid.summary[,-1], iter.max=200,
              5)
fviz_cluster(km.res, 
             stand=F, repel= TRUE,
             data = presid.summary[,-1], xlab="", xaxt="n",
             show.clust.cent=FALSE)

Step 3: Data analysis

3.3. Topic modeling

For topic modeling, we prepare a corpus of sentence snipets as follows. For each speech, we start with sentences and prepare a snipet with a given sentence with the flanking sentences.

corpus.list=sentence.list[2:(nrow(sentence.list)-1), ]
sentence.pre=sentence.list$sentences[1:(nrow(sentence.list)-2)]
sentence.post=sentence.list$sentences[3:(nrow(sentence.list)-1)]
corpus.list$snipets=paste(sentence.pre, corpus.list$sentences, sentence.post, sep=" ")
rm.rows=(1:nrow(corpus.list))[corpus.list$sent.id==1]
rm.rows=c(rm.rows, rm.rows-1)
corpus.list=corpus.list[-rm.rows, ]

Text mining

docs <- Corpus(VectorSource(corpus.list$snipets))
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
It is time for us to realize that we're too great a nation to limit ourselves to small dreams. We're not, as some would have us believe, doomed to an inevitable decline. I do not believe in a fate that will fall on us no matter what we do.

Text basic processing

#remove potentially problematic symbols
docs <-tm_map(docs,content_transformer(tolower))
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
and the principles of action by which i shall endeavor to accomplish this circle of duties it is now proper for me briefly to explain. in administering the laws of congress i shall keep steadily in view the limitations as well as the extent of the executive power, trusting thereby to discharge the functions of my office without transcending its authority. with foreign nations it will be my study to preserve peace and to cultivate friendship on fair and honorable terms, and in the adjustment of any differences that may exist or arise to exhibit the forbearance becoming a powerful nation rather than the sensibility belonging to a gallant people.
#remove punctuation
docs <- tm_map(docs, removePunctuation)
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
in spite of all the criticism which often falls to its lot i do not hesitate to say that there is no more independent and effective legislative body in the world it is and should be jealous of its prerogative i welcome its cooperation and expect to share with it not only the responsibility but the credit for our common effort to secure beneficial legislation
#Strip digits
docs <- tm_map(docs, removeNumbers)
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
genius is free to announce its inventions and discoveries and the hand is free to accomplish whatever the head conceives not incompatible with the rights of a fellowbeing all distinctions of birth or of rank have been abolished all citizens whether native or adopted are placed upon terms of precise equality
#remove stopwords
docs <- tm_map(docs, removeWords, stopwords("english"))
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
 great objects  necessarily connected  can   attained   enlightened exercise   powers   within  appropriate sphere  conformity   public will constitutionally expressed   end  becomes  duty    yield  ready  patriotic submission   laws constitutionally enacted  thereby promote  strengthen  proper confidence   institutions   several states    united states   people   ordained    government  experience  public concerns   observation   life somewhat advanced confirm  opinions long since imbibed     destruction   state governments   annihilation   control   local concerns   people  lead directly  revolution  anarchy  finally  despotism  military domination
#remove whitespace
docs <- tm_map(docs, stripWhitespace)
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
 past third century government passed laws spent money initiated programs previous history pursuing goals full employment better housing excellence education rebuilding cities improving rural areas
#Stem document
docs <- tm_map(docs,stemDocument)
writeLines(as.character(docs[[sample(1:nrow(corpus.list), 1)]]))
scientist now decod blueprint human life cure fear ill seem close hand world longer divid two hostil camp

Topic modeling

Gengerate document-term matrices.

dtm <- DocumentTermMatrix(docs)
#convert rownames to filenames#convert rownames to filenames
rownames(dtm) <- paste(corpus.list$type, corpus.list$File,
                       corpus.list$Term, corpus.list$sent.id, sep="_")
rowTotals <- apply(dtm , 1, sum) #Find the sum of words in each Document
dtm  <- dtm[rowTotals> 0, ]
corpus.list=corpus.list[rowTotals>0, ]

Run LDA

#Set parameters for Gibbs sampling
burnin <- 4000
iter <- 2000
thin <- 500
seed <-list(2003,5,63,100001,765)
nstart <- 5
best <- TRUE

#Number of topics
k <- 15

#Run LDA using Gibbs sampling
ldaOut <-LDA(dtm, k, method="Gibbs", control=list(nstart=nstart, 
                                                 seed = seed, best=best,
                                                 burnin = burnin, iter = iter, 
                                                 thin=thin))
#write out results
#docs to topics
ldaOut.topics <- as.matrix(topics(ldaOut))
table(c(1:k, ldaOut.topics))
write.csv(ldaOut.topics,file=paste("./output/LDAGibbs",k,"DocsToTopics.csv"))

#top 6 terms in each topic
ldaOut.terms <- as.matrix(terms(ldaOut,20))
write.csv(ldaOut.terms,file=paste("./output/LDAGibbs",k,"TopicsToTerms.csv"))

#probabilities associated with each topic assignment
topicProbabilities <- as.data.frame(ldaOut@gamma)
write.csv(topicProbabilities,file=paste("./output/LDAGibbs",k,"TopicProbabilities.csv"))
ldaOut.terms[1,]
  Topic 1   Topic 2   Topic 3   Topic 4   Topic 5   Topic 6   Topic 7   Topic 8   Topic 9  Topic 10  Topic 11 
"freedom"   "great"    "will"    "work"   "shall"   "peopl"   "state"    "time"   "world"     "law"     "war" 
 Topic 12  Topic 13  Topic 14  Topic 15 
 "public"   "everi"  "nation"     "can" 

Based on the most popular terms and the most salient terms for each topic, we assign a hashtag to each topic. This part require manual setup as the topics are likely to change.

topics.hash=c("Freedom", "great", "will", "work", "shall", "people", "state", "time", "world", "law", "war", "public", "every", "nation", "can")
corpus.list$ldatopic=as.vector(ldaOut.topics)
corpus.list$ldahash=topics.hash[ldaOut.topics]
colnames(topicProbabilities)=topics.hash
corpus.list.df=cbind(corpus.list, topicProbabilities)
orders = as.factor(as.numeric(corpus.list.df$FileOrdered)[nrow(corpus.list.df):1])
corpus.list.df<- cbind(corpus.list.df,orders)

Clustering of topics

par(mar=c(1,1,1,1))
topic.summary=tbl_df(corpus.list.df)%>%
              select(orders, Freedom:can)%>%
              group_by(orders)%>%
              summarise_each(funs(mean))
`summarise_each()` is deprecated.
Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
To map `funs` over all variables, use `summarise_all()`
topic.summary=as.data.frame(topic.summary)
rownames(topic.summary)=topic.summary[,1]
topic.plot=c(1, 13, 9, 11, 8, 3, 7)
print(topics.hash[topic.plot])
[1] "Freedom" "every"   "world"   "war"     "time"    "will"    "state"  
heatmap.2(as.matrix(topic.summary[,topic.plot+1]), 
          scale = "column", key=F, 
          col = bluered(100),
          cexRow = 0.9, cexCol = 0.9, margins = c(8, 14),
          trace = "none", density.info = "none")

#Step 4 - Inspect an overall wordcloud

dtm.tidy=tidy(dtm)
print("GeorgeWashington")
[1] "GeorgeWashington"
rang = which(substr(dtm.tidy$document,2,nchar(dtm.tidy$document)-4)=="GeorgeWashington")
dtm.tmp=summarise(group_by(dtm.tidy[rang,], term), sum(count))
wordcloud(dtm.tmp$term, dtm.tmp$`sum(count)`,
          scale=c(5,0.5),
          max.words=100,
          min.freq=1,
          random.order=FALSE,
          rot.per=0.3,
          use.r.layout=T,
          random.color=FALSE,
          colors=brewer.pal(9,"Blues"))

print("ThomasJefferson")
[1] "ThomasJefferson"
rang = which(substr(dtm.tidy$document,2,nchar(dtm.tidy$document)-4)=="ThomasJefferson")
dtm.tmp=summarise(group_by(dtm.tidy[rang,], term), sum(count))
wordcloud(dtm.tmp$term, dtm.tmp$`sum(count)`,
          scale=c(5,0.5),
          max.words=100,
          min.freq=1,
          random.order=FALSE,
          rot.per=0.3,
          use.r.layout=T,
          random.color=FALSE,
          colors=brewer.pal(9,"Blues"))

print("AbrahamLincoln")
[1] "AbrahamLincoln"
rang = which(substr(dtm.tidy$document,2,nchar(dtm.tidy$document)-4)=="AbrahamLincoln")
dtm.tmp=summarise(group_by(dtm.tidy[rang,], term), sum(count))
wordcloud(dtm.tmp$term, dtm.tmp$`sum(count)`,
          scale=c(5,0.5),
          max.words=100,
          min.freq=1,
          random.order=FALSE,
          rot.per=0.3,
          use.r.layout=T,
          random.color=FALSE,
          colors=brewer.pal(9,"Blues"))

print("FranklinDRoosevelt")
[1] "FranklinDRoosevelt"
rang = which(substr(dtm.tidy$document,2,nchar(dtm.tidy$document)-4)=="FranklinDRoosevelt")
dtm.tmp=summarise(group_by(dtm.tidy[rang,], term), sum(count))
wordcloud(dtm.tmp$term, dtm.tmp$`sum(count)`,
          scale=c(5,0.5),
          max.words=100,
          min.freq=1,
          random.order=FALSE,
          rot.per=0.3,
          use.r.layout=T,
          random.color=FALSE,
          colors=brewer.pal(9,"Blues"))

print("BarackObama")
[1] "BarackObama"
rang = which(substr(dtm.tidy$document,2,nchar(dtm.tidy$document)-4)=="BarackObama")
dtm.tmp=summarise(group_by(dtm.tidy[rang,], term), sum(count))
wordcloud(dtm.tmp$term, dtm.tmp$`sum(count)`,
          scale=c(5,0.5),
          max.words=100,
          min.freq=1,
          random.order=FALSE,
          rot.per=0.3,
          use.r.layout=T,
          random.color=FALSE,
          colors=brewer.pal(9,"Blues"))

print("DonaldJTrump")
[1] "DonaldJTrump"
rang = which(substr(dtm.tidy$document,2,nchar(dtm.tidy$document)-4)=="DonaldJTrump")
dtm.tmp=summarise(group_by(dtm.tidy[rang,], term), sum(count))
wordcloud(dtm.tmp$term, dtm.tmp$`sum(count)`,
          scale=c(5,0.5),
          max.words=100,
          min.freq=1,
          random.order=FALSE,
          rot.per=0.3,
          use.r.layout=T,
          random.color=FALSE,
          colors=brewer.pal(9,"Blues"))

My story

We have analyzed the 58 inaugural speeches of presidents. And I have found some interesting things behind their speeches.

To start with, as the father of America, George Washington is a very special president. Not only because his great contribution to America, but also his style of giving speeches. Among all these 40 presidents in our study, George Washington is the most likely to say long sentences. In his inaugural speech, there are only two sentences that have less than 10 words, which are “between duty and advantage” and “From this resolution I have in no instance departed”. We could believe that after listen to the record of George Washington’s inaugural speech, the latter presidents also found his sentence sounds a bit long so they tend to short their sentences when giving speeches. So it becomes a trend that as time goes by, presidents tend to use shorter sentences and less words in their inaugural speech. As we can see, shorter sentences and less words make a speech more precise and eazy for audiences. And short words and sentences are more likely to cause emotional resonance, which may help them wins the trust of people.

However, George Washington and Thomas Jefferson lived in the same period but they showed quite different ways of giving speech. Unlike George Washington, Thomas Jefferson uses shorter sentences compared to the presidents in his near furture. Let’s recall from their teenager environment. George Washington lived in the countryside and had never got education until 15 years old. Then he learned from the local tutor and showed talent in math, geometry and measurement. We may consider this as an explaination of George Washington’s inaugural speech that he is good at solving complicated problems and can easily undertand long sentences. As for Thomas Jefferson, he recieved classical education and learned history and politics, which may made him a good speaker at his period. And for now it almost becomes a trend that the inaugural speech uses short sentences. Maybe it is because modern people are too tired to listen to long sentences.

Another interesting discover is that presidents’ words always reflect their time age and people’s hope. For the first two presidents, we can see from the word cloud that they focused more on equality of every people. They lived in a period that America was just founded. It became very important that every individual’s right was treated equally. While when it came to the time of Abraham Lincoln who lead the civil war and Franklin D. Roosevelt who joined the second world war. Their speeches were strongly related to the topic of war. We can find words about union or states in Abraham Lincoln’s speech while peace in Franklin D. Roosevelt’s speeches. Now let’s think about Barack Obama and Donald Trump. They both have the willing to recover from 2008 economic crisis, so they talked more about past, together and America, which encouraged people to fight for the hard days together.

Last but not least, from the clustering of emotions, we also found that the positive emotions is the most used feeling in inaugural speech. It is not hard to explain that only if the speaker showes trustful quality to audiences, the audiences will trust you as a good president. What’s more, we also can see some relationship between emotion clustering and party labels. The ones share the same idea will show smilar emotions when giving speeches.

Let’s use the most emotion used in inaugural speech to end our study, trust people, people trust you.

LS0tCnRpdGxlOiAiUHJvamVjdDEiCmF1dGhvcjogIkZhbiBZYW5nIgpkYXRlOiAiMDEtMzAtMjAxOCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKIyBTdGVwIDA6IGNoZWNrIGFuZCBpbnN0YWxsIG5lZWRlZCBwYWNrYWdlcy4gTG9hZCB0aGUgbGlicmFyaWVzIGFuZCBmdW5jdGlvbnMuIAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgcGFja2FnZXMudXNlZD1jKCJydmVzdCIsICJ0aWJibGUiLCAicWRhcCIsIAojICAgICAgICAgICAgICAgICAic2VudGltZW50ciIsICJncGxvdHMiLCAiZHBseXIiLAojICAgICAgICAgICAgICAgICAidG0iLCAic3l1emhldCIsICJmYWN0b2V4dHJhIiwgCiMgICAgICAgICAgICAgICAgICJiZWVzd2FybSIsICJzY2FsZXMiLCAiUkNvbG9yQnJld2VyIiwKIyAgICAgICAgICAgICAgICAgIlJBTk4iLCAidG0iLCAidG9waWNtb2RlbHMiKQojIAojICMgY2hlY2sgcGFja2FnZXMgdGhhdCBuZWVkIHRvIGJlIGluc3RhbGxlZC4KIyBwYWNrYWdlcy5uZWVkZWQ9c2V0ZGlmZihwYWNrYWdlcy51c2VkLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnNlY3QoaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFja2FnZXMudXNlZCkpCiMgIyBpbnN0YWxsIGFkZGl0aW9uYWwgcGFja2FnZXMKIyBpZihsZW5ndGgocGFja2FnZXMubmVlZGVkKT4wKXsKIyAgIGluc3RhbGwucGFja2FnZXMocGFja2FnZXMubmVlZGVkLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQojIH0KCiMgbG9hZCBwYWNrYWdlcwpsaWJyYXJ5KCJydmVzdCIpCmxpYnJhcnkoInRpYmJsZSIpCiMgWW91IG1heSBuZWVkIHRvIHJ1bgojc3lzdGVtKCJsbiAtZiAtcyAkKC91c3IvbGliZXhlYy9qYXZhX2hvbWUpL2pyZS9saWIvc2VydmVyL2xpYmp2bS5keWxpYiAvdXNyL2xvY2FsL2xpYiIpCiMgc3VkbyBsbiAtZiAtcyAkKC91c3IvbGliZXhlYy9qYXZhX2hvbWUpL2pyZS9saWIvc2VydmVyL2xpYmp2bS5keWxpYiAvdXNyL2xvY2FsL2xpYgojIGluIG9yZGVyIHRvIGxvYWQgcWRhcApsaWJyYXJ5KCJxZGFwIikKbGlicmFyeSgic2VudGltZW50ciIpCmxpYnJhcnkoImdwbG90cyIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgidG0iKQpsaWJyYXJ5KCJzeXV6aGV0IikKbGlicmFyeSgiZmFjdG9leHRyYSIpCmxpYnJhcnkoImJlZXN3YXJtIikKbGlicmFyeSgic2NhbGVzIikKbGlicmFyeSgiUkNvbG9yQnJld2VyIikKbGlicmFyeSgiUkFOTiIpCmxpYnJhcnkoInRtIikKbGlicmFyeSgidG9waWNtb2RlbHMiKQoKbGlicmFyeSh3b3JkY2xvdWQpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHRpZHl0ZXh0KQoKbGlicmFyeSgieGxzeCIpCmxpYnJhcnkoImdncGxvdDIiKQoKc291cmNlKCIuL2xpYi9wbG90c3RhY2tlZC5SIikKc291cmNlKCIuL2xpYi9zcGVlY2hGdW5jcy5SIikKYGBgClRoaXMgbm90ZWJvb2sgd2FzIHByZXBhcmVkIHdpdGggdGhlIGZvbGxvd2luZyBlbnZpcm9ubWVudGFsIHNldHRpbmdzLgoKYGBge3J9CnByaW50KFIudmVyc2lvbikKYGBgCgojIFN0ZXAgMTogRGF0YSBoYXJ2ZXN0OgoKRmlyc3QgaW1wb3J0IGFsbCBkYXRhIG5lZWRlZDogSW5hdWd1YXRpb25EYXRlcy50eHQsIEluYXVndXJhdGlvbkluZm8ueGxzeCBhbmQgYWxsIHNwZWVjaGVzIHRleHQuCmBgYHtyLHdhcm5pbmc9RkFMU0V9CmluYXVnLmRhdGVzIDwtIHJlYWQudGFibGUoIi4vZGF0YS9JbmF1Z3VhdGlvbkRhdGVzLnR4dCIsaGVhZGVyPVRSVUUsc2VwPSJcdCIpCmluYXVnLmluZm8gPC0gcmVhZC54bHN4KCIuL2RhdGEvSW5hdWd1cmF0aW9uSW5mby54bHN4IixzaGVldE5hbWU9IlNoZWV0MSIsaGVhZGVyPVQsc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQppbmF1Zy5pbmZvJFdvcmRzIDwtIGFzLm51bWVyaWMoaW5hdWcuaW5mbyRXb3JkcykKCmZpbGVuYW1lcyA9IGxpc3QuZmlsZXMoIi4vZGF0YS9JbmF1Z3VyYWxTcGVlY2hlcyIpICNnZXQgYWxsIGZpbGUgbmFtZQpkaXIgPSBwYXN0ZSgiLi9kYXRhL0luYXVndXJhbFNwZWVjaGVzLyIsZmlsZW5hbWVzLHNlcD0iIikKbiA9IGxlbmd0aChkaXIpCnNwZWVjaGVzID0gbGlzdCgpCmZvciAoaSBpbiAxOm4pewogIGZpbGVuYW1lID0gcGFzdGUoIi4vZGF0YS9JbmF1Z3VyYWxTcGVlY2hlcy9pbmF1ZyIsaW5hdWcuaW5mbyRGaWxlW2ldLCItIixpbmF1Zy5pbmZvJFRlcm1baV0sIi50eHQiLHNlcD0iIikKICBuZXcuZGF0YSA9IHBhc3RlKHJlYWRMaW5lcyhmaWxlbmFtZSwgbj0tMSwgc2tpcE51bD1UUlVFKSxjb2xsYXBzZT0iICIpCiAgc3BlZWNoZXMgPSBjKHNwZWVjaGVzLG5ldy5kYXRhKQp9Cm5hbWVzKHNwZWVjaGVzKSA8LSBwYXN0ZShpbmF1Zy5pbmZvJEZpbGUsIGluYXVnLmluZm8kVGVybSxzZXA9Ii0iKQpgYGAKCiMgU3RlcCAyOiBkYXRhIFByb2Nlc3NpbmcgLS0tIGdlbmVyYXRlIGxpc3Qgb2Ygc2VudGVuY2VzCgpVc2UgIj8iLCAiLiIsICIhIiwgInwiLCI7IiBhcyBzdG9wIHBvaW50IG9mIG9uZSBzZW50ZW5jZSBhbmQgZXh0cmFjdCBhbGwgc2VudGVuY2VzIGZyb20gc3BlZWNoZXMuCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzZW50ZW5jZS5saXN0PU5VTEwKZm9yKGkgaW4gMTo1OCl7CiAgc2VudGVuY2VzPXNlbnRfZGV0ZWN0KHNwZWVjaGVzW2ldLAogICAgICAgICAgICAgICAgICAgICAgICBlbmRtYXJrcyA9IGMoIj8iLCAiLiIsICIhIiwgInwiLCI7IikpCiAgaWYobGVuZ3RoKHNlbnRlbmNlcyk+MCl7CiAgICBlbW90aW9ucz1nZXRfbnJjX3NlbnRpbWVudChzZW50ZW5jZXMpCiAgICB3b3JkLmNvdW50PXdvcmRfY291bnQoc2VudGVuY2VzKQogICAgZW1vdGlvbnM9ZGlhZygxLyh3b3JkLmNvdW50KzAuMDEpKSUqJWFzLm1hdHJpeChlbW90aW9ucykKICAgIHNlbnRlbmNlLmxpc3Q9cmJpbmQoc2VudGVuY2UubGlzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgIGNiaW5kKGluYXVnLmluZm9baSwtbmNvbChpbmF1Zy5pbmZvKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbnRlbmNlcz1hcy5jaGFyYWN0ZXIoc2VudGVuY2VzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmQuY291bnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVtb3Rpb25zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZW50LmlkPTE6bGVuZ3RoKHNlbnRlbmNlcykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgKQogIH0KfQpgYGAKCkRlbGV0ZSBhbGwgbm9uLXNlbnRlbmNlcyByZXN1bHRlZCBieSBlcnJvbmVvdXMgZXh0cmEgZW5kLW9mLXNlbnRlbmNlIG1hcmtzLiAKYGBge3J9CnNlbnRlbmNlLmxpc3Q9CiAgc2VudGVuY2UubGlzdCU+JQogIGZpbHRlcighaXMubmEod29yZC5jb3VudCkpIApgYGAKCiMgU3RlcCAzOiBEYXRhIGFuYWx5c2lzCiMjIDMuMS4gdG90YWwgbnVtYmVyIG9mIHdvcmRzCkJlZm9yZSB3ZSBhbmFseXplIGxlbmd0aCBvZiBzaW5nbGUgc2VudGVuY2VzLCBsZXQncyBoYXZlIGFuIHByZXd2aWV3IG9mIHRvdGFsIG51bWJlciBvZiB3b3JkcyBpbiBhIHNwZWVjaC4gRHJhdyBhIHBsb3Qgb2YgbGVuZ3RoIG9mIHNwZWVjaCBhZ2FpbnN0IHRoZWlyIHRpbWUgb3JkZXIuCmBgYHtyLHdhcm5pbmc9RkFMU0V9CmdncGxvdChpbmF1Zy5pbmZvKSArCiAgZ2VvbV9wb2ludChhZXMoMTo1OCxXb3JkcykpICsKICBnZW9tX3Ntb290aChhZXMoMTo1OCxXb3JkcykpCmBgYApOb3RpY2UgdGhhdCBhcyB0aW1lIHdlbnQgYnksIHRoZSB0b3RhbCBudW1iZXIgb2Ygd29yZHMgaW4gYSBzcGVlY2ggdGVuZCB0byBiZSBsZXNzIGFuZCBjb252ZXJnZXMgdG8gYXJvdW5kIDIwMDAuIEFzIHdlIGtub3csIHNob3J0ZXIgc3BlZWNoIGxlYWRzIHRvIHNob3J0ZXIgdGltZSBzY2FsZS4gV2UgY2FuIGRyYWZ0bHkgY29uY2x1ZGUgdGhhdCB0aGUgc3BlZWNoZXMgdGVuZCB0byBiZSBtb3JlIGNvbmNpc2UuIFRoZSBzcGVha2VycyBrbmV3IHRoYXQgdGhlIGxvbmdlciB0aGVpciBzcGVlY2ggaXMsIHRoZSBsZXNzIGludGVyZXN0IHBlb3BsZSBoYXZlIHRvIGhlYXIgdGhlaXIgd29yZHMuIEJ1dCB0b28gbGVzcyB3b3JkcyBjYW4gbm90IHByZWNpc2VseSBjb252ZXkgdGhlaXIgcG9saXRpY2FsIHRob3VnaHRzLiBUaGVyZWZvcmUsIHRoZSBudW1iZXIgb2Ygd29yZHMgaW4gYSBzcGVlY2ggaGF2ZSB0aGUgdGVuZGVuY3kgdG8gYmUgd2l0aGluIHNvbWUgY2VydGFpbiByYW5nZS4KCiMjIDMuMi4gbGVuZ3RoIG9mIHNlbnRlbmNlcwpOb3cgd2Ugd2FudCB0byBmaW5kIHNvbWV0aGluZyBhYm91dCB0aGUgbGVuZ3RoIG9mIHNlbnRlbmNlcy4KYGBge3IsIGZpZy53aWR0aCA9IDMsIGZpZy5oZWlnaHQgPSAzLjR9CnNlbnRlbmNlLmxpc3QkVGltZU9yZGVyZWQ9cmVvcmRlcihzZW50ZW5jZS5saXN0JEZpbGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxOm5yb3coc2VudGVuY2UubGlzdCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlcj1UKQp0YWlsKHNlbnRlbmNlLmxpc3QkVGltZU9yZGVyZWQsMTUwKQpiZWVzd2FybSh3b3JkLmNvdW50flRpbWVPcmRlcmVkLAogICAgICAgICBkYXRhPXNlbnRlbmNlLmxpc3QsCiAgICAgICAgIGhvcml6b250YWwgPSBUUlVFLCAKICAgICAgICAgcGNoPTE2LCBjb2w9YWxwaGEoYnJld2VyLnBhbCg5LCAiU2V0MSIpLCAwLjYpLCAKICAgICAgICAgY2V4PTAuNTUsIGNleC5heGlzPTAuNDQsIGNleC5sYWI9MC44LAogICAgICAgICBzcGFjaW5nPTEuMi9ubGV2ZWxzKHNlbnRlbmNlLmxpc3QkRmlsZU9yZGVyZWQpLAogICAgICAgICBsYXM9MiwgeGxhYj0iTnVtYmVyIG9mIHdvcmRzIGluIGEgc2VudGVuY2UuIiwgeWxhYj0iIiwKICAgICAgICAgbWFpbj0iSW5hdWd1cmFsIFNwZWVjaGVzIikKYGBgCgpBcyB3ZSBjYW4gc2VlIG9uIGFib3ZlIHBsb3QsIHktY29vcmRpbmF0ZSBmb2xsb3dzIHRoZSB0aW1lIG9yZGVyLiBHZW9yZ2VXYXNoaW5ndG9uIGlzIHRoZSBmaXJzdCBwcmVzaWRlbnQgd2hpbGUgRG9uYWxkSlRydW1wIGlzIHRoZSBwcmVzZW50IHByZXNpZGVudC4gV2UgZm91bmQgdGhhdCBhcyB0aW1lIHdlbnQgYnksIHRoZSBudW1iZXIgb2Ygd29yZHMgaW4gYSBzZW50ZW5jZSBiZWNvbWVzIGxlc3MgYW5kIGxlc3MuIFRoZSBwcmVzaWRlbnRzIHRlbmQgdG8gdXNlIGxlc3Mgd29yZHMgaW4gYSBzZW50ZW5jZS4KCldoYXQgYXJlIHRoZXNlIHNob3J0IHNlbnRlbmNlcz8KYGBge3J9CnNlbnRlbmNlLmxpc3QlPiUKICBmaWx0ZXIoRmlsZT09Ikdlb3JnZVdhc2hpbmd0b24iLCAKICAgICAgICAgd29yZC5jb3VudDw9MTAmd29yZC5jb3VudD4xKSU+JQogIHNlbGVjdChzZW50ZW5jZXMpJT4lc2FtcGxlX24oMikKCnNlbnRlbmNlLmxpc3QlPiUKICBmaWx0ZXIoRmlsZT09IlRob21hc0plZmZlcnNvbiIsIAogICAgICAgICB3b3JkLmNvdW50PD01JndvcmQuY291bnQ+MSklPiUKICBzZWxlY3Qoc2VudGVuY2VzKSU+JXNhbXBsZV9uKDUpCgpzZW50ZW5jZS5saXN0JT4lCiAgZmlsdGVyKEZpbGU9PSJBYnJhaGFtTGluY29sbiIsIAogICAgICAgICB3b3JkLmNvdW50PD01JndvcmQuY291bnQ+MSklPiUKICBzZWxlY3Qoc2VudGVuY2VzKSU+JXNhbXBsZV9uKDQpCgpzZW50ZW5jZS5saXN0JT4lCiAgZmlsdGVyKEZpbGU9PSJGcmFua2xpbkRSb29zZXZlbHQiLCAKICAgICAgICAgd29yZC5jb3VudDw9NSZ3b3JkLmNvdW50PjEpJT4lCiAgc2VsZWN0KHNlbnRlbmNlcyklPiVzYW1wbGVfbig1KQoKc2VudGVuY2UubGlzdCU+JQogIGZpbHRlcihGaWxlPT0iQmFyYWNrT2JhbWEiLCAKICAgICAgICAgd29yZC5jb3VudDw9NSZ3b3JkLmNvdW50PjEpJT4lCiAgc2VsZWN0KHNlbnRlbmNlcyklPiVzYW1wbGVfbig1KQoKc2VudGVuY2UubGlzdCU+JQogIGZpbHRlcihGaWxlPT0iRG9uYWxkSlRydW1wIiwgCiAgICAgICAgIHdvcmQuY291bnQ8PTUmd29yZC5jb3VudD4xKSU+JQogIHNlbGVjdChzZW50ZW5jZXMpJT4lc2FtcGxlX24oNSkKYGBgCkxldCdzIHNlbGVjdCA2IHZlcnkgZmFtb3VzIHByZXNpZGVudHMgYW1vbmcgQW1lcmljYW4gaGlzdG9yeS4gRWFjaCBvZiB0aGVtIHJlcHJlc2VudHMgZGlmZmVyZW50IHRpbWUgcGVyaW9kLiBHZW9yZ2UgV2FzaGluZ3RvbiByZXByZXNlbnRzIHRoZSB2ZXJ5IGJlZ2lubmluZyBvZiBBbWVyaWNhbiBoaXN0b3J5IHdoaWxlIERvbmFsZEogVHJ1bXAgc3RhbmRzIGZvciB0aGUgbGFzdGVzdC4KCkZyb20gdGhlIG91dHB1dCBhYm92ZSwgR2VvcmdlIFdhc2hpbmd0b24gdXNlZCBhIHNlbnRlbmNlIHdpdGggbGVzcyB0aGFuIDEwIHdvcmRzIG9ubHkgdHdpY2Ugd2hpbGUgRG9uYWxkSiBUcnVtcCB1c2VkIGEgc2VudGVuY2Ugd2l0aCBsZXNzIHRoYW4gNSB3b3JkcyBtb3JlIHRoYW4gNSB0aW1lcy4gR2VvcmdlIFdhc2hpbmd0b24gYW5kIFRob21hcyBKZWZmZXJzb24gdGFsa3MgbW9yZSBhYm91dCBmcmVlZG9tIGFuZCB0aGUgZm91bmRhdGlvbiBvZiBBbWVyaWNhLiBBYnJhaGFtIExpbmNvbG4gYW5kIEZyYW5rbGluIEQuIFJvb3NldmVsdCB3aG8gd2VyZSBwcmVzaWRlbnRzIGR1cmluZyB3YXIgcGVyaW9kLCB0aGVpciB3b3JzZHMgZmlnaHQgZm9yIHBlYWNlIGFuZCBlbmNvdXJhZ2UgcGVvcGxlIGR1cmluZyBoYXJkIGRheXMuIEFzIGZvciBEb25hbGRKIFRydW1wIGFuZCBCYXJhY2sgT2JhbWEsIHdobyBhcmUgcHJlc2lkZW50cyBkdXJpbmcgcGVhY2UgcGVyaW9kIGJ1dCBzdWZmZXJlZCBmcm9tIGVjb25vbWljIGNyaXNpcywgdGhlaXIgd29yZHMgZm9jdXNlcyBtb3JlIG9uIHJlY292ZXJ5IG9mIGVjb25vbXkuCgpBcyBwYWNlIG9mIGhpc3RvcnkgcHVzaGVzIGZvcndhcmQsIHRoZSBBbWVyaWNhbiBwZW9wbGUgZmFjZWQgZGlmZmVyZW50IHByb2JsZW1zIGR1cmluZyBkaWZmZXJlbnQgcGVyaW9kIGFuZCB0aGVpciBwcmVzaWRlbnRzIGZvY3VzZWQgb24gdGhlIG1vc3QgaW1wcmVzc2l2ZSB0b3BpYyBmb3IgcGVvcGxlJ3MgbGlmZS4KCiMgU3RlcCAzOiBEYXRhIGFuYWx5c2lzCiMjIDMuMi4gc2VudGltZW50IGFuYWxzaXMKCiMjIyBTZW50ZW5jZSBsZW5ndGggdmFyaWF0aW9uIG92ZXIgdGhlIGNvdXJzZSBvZiB0aGUgc3BlZWNoLCB3aXRoIGVtb3Rpb25zLiAKCmBgYHtyLCBmaWcuaGVpZ2h0PTIuNSwgZmlnLndpZHRoPTJ9CnBhcihtZnJvdz1jKDYsMSksIG1hcj1jKDEsMCwyLDApLCBidHk9Im4iLCB4YXh0PSJuIiwgeWF4dD0ibiIsIGZvbnQubWFpbj0xKQoKZi5wbG90c2VudC5sZW4oSW4ubGlzdD1zZW50ZW5jZS5saXN0LCBJbkZpbGU9Ikdlb3JnZVdhc2hpbmd0b24iLCAKICAgICAgICAgICAgICAgUHJlc2lkZW50PSJHZW9yZ2UgV2FzaGluZ3RvbiIpCgpmLnBsb3RzZW50LmxlbihJbi5saXN0PXNlbnRlbmNlLmxpc3QsIEluRmlsZT0iVGhvbWFzSmVmZmVyc29uIiwgCiAgICAgICAgICAgICAgIFByZXNpZGVudD0iVGhvbWFzIEplZmZlcnNvbiIpCgpmLnBsb3RzZW50LmxlbihJbi5saXN0PXNlbnRlbmNlLmxpc3QsIEluRmlsZT0iQWJyYWhhbUxpbmNvbG4iLCAKICAgICAgICAgICAgICAgUHJlc2lkZW50PSJBYnJhaGFtIExpbmNvbG4iKQoKZi5wbG90c2VudC5sZW4oSW4ubGlzdD1zZW50ZW5jZS5saXN0LCBJbkZpbGU9IkZyYW5rbGluRFJvb3NldmVsdCIsIAogICAgICAgICAgICAgICBQcmVzaWRlbnQ9IkZyYW5rbGluIEQuIFJvb3NldmVsdCIpCgpmLnBsb3RzZW50LmxlbihJbi5saXN0PXNlbnRlbmNlLmxpc3QsIEluRmlsZT0iQmFyYWNrT2JhbWEiLCAKICAgICAgICAgICAgICAgUHJlc2lkZW50PSJCYXJhY2sgT2JhbWEiKQoKZi5wbG90c2VudC5sZW4oSW4ubGlzdD1zZW50ZW5jZS5saXN0LCBJbkZpbGU9IkRvbmFsZEpUcnVtcCIsIAogICAgICAgICAgICAgICBQcmVzaWRlbnQ9IkRvbmFsZCBUcnVtcCIpCmBgYApXZSBjYW4gc2VlIHRoYXQgdGhlIG9sZGVyIHByZXNpZGVudHMoR2VvcmdlIFdhc2hpbmd0b24gYW5kIFRob21hcyBKZWZmZXJzb24pIHRlbmQgdG8gdXNlIGxvbmcgc2VudGVuY2VzIHRvIGV4cHJlc3MgdGhlaXIgb3BpbmlvbnMgcHJlY2lzZWx5LiBXaGlsZSB0aGUgbmV3ZXIgcHJlc2lkZW50cyhCYXJhYyBrT2JhbWEgYW5kIERvbmFsZCBUcnVtcCkgdGVuZCB0byB1c2Ugc2hvcnQgc2VudGVuY2VzIHRvIGVuY291cmFnZSBwZW9wbGUgYW5kIGNvbnZleSB0aGVpciBmZWVsaW5ncyB0byBnZXQgZW1vdGlvbmFsIHJlc29uYW5jZS4KCiMjIyMgV2hhdCBhcmUgdGhlIGVtb3Rpb25hbGx5IGNoYXJnZWQgc2VudGVuY2VzPwoKYGBge3J9CnByaW50KCJHZW9yZ2UgV2FzaGluZ3RvbiIpCnNwZWVjaC5kZj10YmxfZGYoc2VudGVuY2UubGlzdCklPiUKICBmaWx0ZXIoRmlsZT09Ikdlb3JnZVdhc2hpbmd0b24iLCB3b3JkLmNvdW50Pj00KSU+JQogIHNlbGVjdChzZW50ZW5jZXMsIGFuZ2VyOnRydXN0KQpzcGVlY2guZGY9YXMuZGF0YS5mcmFtZShzcGVlY2guZGYpCmFzLmNoYXJhY3RlcihzcGVlY2guZGYkc2VudGVuY2VzW2FwcGx5KHNwZWVjaC5kZlssLTFdLCAyLCB3aGljaC5tYXgpXSkKCnByaW50KCJUaG9tYXMgSmVmZmVyc29uIikKc3BlZWNoLmRmPXRibF9kZihzZW50ZW5jZS5saXN0KSU+JQogIGZpbHRlcihGaWxlPT0iVGhvbWFzSmVmZmVyc29uIiwgd29yZC5jb3VudD49NSklPiUKICBzZWxlY3Qoc2VudGVuY2VzLCBhbmdlcjp0cnVzdCkKc3BlZWNoLmRmPWFzLmRhdGEuZnJhbWUoc3BlZWNoLmRmKQphcy5jaGFyYWN0ZXIoc3BlZWNoLmRmJHNlbnRlbmNlc1thcHBseShzcGVlY2guZGZbLC0xXSwgMiwgd2hpY2gubWF4KV0pCgpwcmludCgiQWJyYWhhbSBMaW5jb2xuIikKc3BlZWNoLmRmPXRibF9kZihzZW50ZW5jZS5saXN0KSU+JQogIGZpbHRlcihGaWxlPT0iQWJyYWhhbUxpbmNvbG4iLCB3b3JkLmNvdW50Pj00KSU+JQogIHNlbGVjdChzZW50ZW5jZXMsIGFuZ2VyOnRydXN0KQpzcGVlY2guZGY9YXMuZGF0YS5mcmFtZShzcGVlY2guZGYpCmFzLmNoYXJhY3RlcihzcGVlY2guZGYkc2VudGVuY2VzW2FwcGx5KHNwZWVjaC5kZlssLTFdLCAyLCB3aGljaC5tYXgpXSkKCnByaW50KCJGcmFua2xpbiBELiBSb29zZXZlbHQiKQpzcGVlY2guZGY9dGJsX2RmKHNlbnRlbmNlLmxpc3QpJT4lCiAgZmlsdGVyKEZpbGU9PSJGcmFua2xpbkRSb29zZXZlbHQiLCB3b3JkLmNvdW50Pj00KSU+JQogIHNlbGVjdChzZW50ZW5jZXMsIGFuZ2VyOnRydXN0KQpzcGVlY2guZGY9YXMuZGF0YS5mcmFtZShzcGVlY2guZGYpCmFzLmNoYXJhY3RlcihzcGVlY2guZGYkc2VudGVuY2VzW2FwcGx5KHNwZWVjaC5kZlssLTFdLCAyLCB3aGljaC5tYXgpXSkKCnByaW50KCJCYXJhY2sgT2JhbWEiKQpzcGVlY2guZGY9dGJsX2RmKHNlbnRlbmNlLmxpc3QpJT4lCiAgZmlsdGVyKEZpbGU9PSJCYXJhY2tPYmFtYSIsIHdvcmQuY291bnQ+PTQpJT4lCiAgc2VsZWN0KHNlbnRlbmNlcywgYW5nZXI6dHJ1c3QpCnNwZWVjaC5kZj1hcy5kYXRhLmZyYW1lKHNwZWVjaC5kZikKYXMuY2hhcmFjdGVyKHNwZWVjaC5kZiRzZW50ZW5jZXNbYXBwbHkoc3BlZWNoLmRmWywtMV0sIDIsIHdoaWNoLm1heCldKQoKcHJpbnQoIkRvbmFsZCBUcnVtcCIpCnNwZWVjaC5kZj10YmxfZGYoc2VudGVuY2UubGlzdCklPiUKICBmaWx0ZXIoRmlsZT09IkRvbmFsZEpUcnVtcCIsIHdvcmQuY291bnQ+PTUpJT4lCiAgc2VsZWN0KHNlbnRlbmNlcywgYW5nZXI6dHJ1c3QpCnNwZWVjaC5kZj1hcy5kYXRhLmZyYW1lKHNwZWVjaC5kZikKYXMuY2hhcmFjdGVyKHNwZWVjaC5kZiRzZW50ZW5jZXNbYXBwbHkoc3BlZWNoLmRmWywtMV0sIDIsIHdoaWNoLm1heCldKQoKYGBgCgojIyMgQ2x1c3RlcmluZyBvZiBlbW90aW9ucwpgYGB7ciwgZmlnLndpZHRoPTIsIGZpZy5oZWlnaHQ9Mn0KCnBhcihtYXI9Yyg0LCA2LCAyLCAxKSkKZW1vLm1lYW5zPWNvbE1lYW5zKHNlbGVjdChzZW50ZW5jZS5saXN0LCBhbmdlcjp0cnVzdCk+MC4wMSkKY29sLnVzZT1jKCJyZWQyIiwgImRhcmtnb2xkZW5yb2QxIiwgCiAgICAgICAgICAgICJjaGFydHJldXNlMyIsICJibHVldmlvbGV0IiwKICAgICAgICAgICAgImRhcmtnb2xkZW5yb2QyIiwgImRvZGdlcmJsdWUzIiwgCiAgICAgICAgICAgICJkYXJrZ29sZGVucm9kMSIsICJkYXJrZ29sZGVucm9kMSIpCmJhcnBsb3QoZW1vLm1lYW5zW29yZGVyKGVtby5tZWFucyldLCBsYXM9MiwgY29sPWNvbC51c2Vbb3JkZXIoZW1vLm1lYW5zKV0sIGhvcml6PVQsIG1haW49IkluYXVndXJhbCBTcGVlY2hlcyIpCmBgYApXZSBjYW4gZmluZCB0aGF0IGEgcHJlc2lkZW50IG11c3QgY29udmV5IHBvc2l0aXZlIGZlZWxpbmdzIGxpa2UgdHJ1c3QgaW4gb3JkZXIgdG8gZ2V0IHBlb3BsZSdzIHRydXN0LgpgYGB7ciwgZmlnLmhlaWdodD0zLjMsIGZpZy53aWR0aD0zLjd9CnByZXNpZC5zdW1tYXJ5PXRibF9kZihzZW50ZW5jZS5saXN0KSU+JQogIGdyb3VwX2J5KEZpbGUpJT4lCiAgc3VtbWFyaXNlKAogICAgYW5nZXI9bWVhbihhbmdlciksCiAgICBhbnRpY2lwYXRpb249bWVhbihhbnRpY2lwYXRpb24pLAogICAgZGlzZ3VzdD1tZWFuKGRpc2d1c3QpLAogICAgZmVhcj1tZWFuKGZlYXIpLAogICAgam95PW1lYW4oam95KSwKICAgIHNhZG5lc3M9bWVhbihzYWRuZXNzKSwKICAgIHN1cnByaXNlPW1lYW4oc3VycHJpc2UpLAogICAgdHJ1c3Q9bWVhbih0cnVzdCkKICApCgpwcmVzaWQuc3VtbWFyeT1hcy5kYXRhLmZyYW1lKHByZXNpZC5zdW1tYXJ5KQpyb3duYW1lcyhwcmVzaWQuc3VtbWFyeSk9YXMuY2hhcmFjdGVyKChwcmVzaWQuc3VtbWFyeVssMV0pKQprbS5yZXM9a21lYW5zKHByZXNpZC5zdW1tYXJ5WywtMV0sIGl0ZXIubWF4PTIwMCwKICAgICAgICAgICAgICA1KQpmdml6X2NsdXN0ZXIoa20ucmVzLCAKICAgICAgICAgICAgIHN0YW5kPUYsIHJlcGVsPSBUUlVFLAogICAgICAgICAgICAgZGF0YSA9IHByZXNpZC5zdW1tYXJ5WywtMV0sIHhsYWI9IiIsIHhheHQ9Im4iLAogICAgICAgICAgICAgc2hvdy5jbHVzdC5jZW50PUZBTFNFKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTMuMywgZmlnLndpZHRoPTMuN30KcHJlc2lkLnRtcD10YmxfZGYoc2VudGVuY2UubGlzdFtpbmF1Zy5pbmZvJFBhcnR5PT0iRGVtb2NyYXRpYyIsXSklPiUKICBncm91cF9ieShGaWxlKSU+JQogIHN1bW1hcmlzZSgKICAgIGFuZ2VyPW1lYW4oYW5nZXIpLAogICAgYW50aWNpcGF0aW9uPW1lYW4oYW50aWNpcGF0aW9uKSwKICAgIGRpc2d1c3Q9bWVhbihkaXNndXN0KSwKICAgIGZlYXI9bWVhbihmZWFyKSwKICAgIGpveT1tZWFuKGpveSksCiAgICBzYWRuZXNzPW1lYW4oc2FkbmVzcyksCiAgICBzdXJwcmlzZT1tZWFuKHN1cnByaXNlKSwKICAgIHRydXN0PW1lYW4odHJ1c3QpCiAgKQppbmF1Zy5pbmZvJFBhcnR5CnByZXNpZC5zdW1tYXJ5PWFzLmRhdGEuZnJhbWUocHJlc2lkLnN1bW1hcnkpCnJvd25hbWVzKHByZXNpZC5zdW1tYXJ5KT1hcy5jaGFyYWN0ZXIoKHByZXNpZC5zdW1tYXJ5WywxXSkpCmttLnJlcz1rbWVhbnMocHJlc2lkLnN1bW1hcnlbLC0xXSwgaXRlci5tYXg9MjAwLAogICAgICAgICAgICAgIDUpCmZ2aXpfY2x1c3RlcihrbS5yZXMsIAogICAgICAgICAgICAgc3RhbmQ9RiwgcmVwZWw9IFRSVUUsCiAgICAgICAgICAgICBkYXRhID0gcHJlc2lkLnN1bW1hcnlbLC0xXSwgeGxhYj0iRGVtb2NyYXRpYyBwYXJ0eSIsIHhheHQ9Im4iLAogICAgICAgICAgICAgc2hvdy5jbHVzdC5jZW50PUZBTFNFKQpgYGAKYGBge3IsIGZpZy5oZWlnaHQ9My4zLCBmaWcud2lkdGg9My43fQpwcmVzaWQudG1wPXRibF9kZihzZW50ZW5jZS5saXN0W2luYXVnLmluZm8kUGFydHk9PSJSZXB1YmxpY2FuIixdKSU+JQogIGdyb3VwX2J5KEZpbGUpJT4lCiAgc3VtbWFyaXNlKAogICAgYW5nZXI9bWVhbihhbmdlciksCiAgICBhbnRpY2lwYXRpb249bWVhbihhbnRpY2lwYXRpb24pLAogICAgZGlzZ3VzdD1tZWFuKGRpc2d1c3QpLAogICAgZmVhcj1tZWFuKGZlYXIpLAogICAgam95PW1lYW4oam95KSwKICAgIHNhZG5lc3M9bWVhbihzYWRuZXNzKSwKICAgIHN1cnByaXNlPW1lYW4oc3VycHJpc2UpLAogICAgdHJ1c3Q9bWVhbih0cnVzdCkKICApCmluYXVnLmluZm8kUGFydHkKcHJlc2lkLnN1bW1hcnk9YXMuZGF0YS5mcmFtZShwcmVzaWQuc3VtbWFyeSkKcm93bmFtZXMocHJlc2lkLnN1bW1hcnkpPWFzLmNoYXJhY3RlcigocHJlc2lkLnN1bW1hcnlbLDFdKSkKa20ucmVzPWttZWFucyhwcmVzaWQuc3VtbWFyeVssLTFdLCBpdGVyLm1heD0yMDAsCiAgICAgICAgICAgICAgNSkKZnZpel9jbHVzdGVyKGttLnJlcywgCiAgICAgICAgICAgICBzdGFuZD1GLCByZXBlbD0gVFJVRSwKICAgICAgICAgICAgIGRhdGEgPSBwcmVzaWQuc3VtbWFyeVssLTFdLCB4bGFiPSJSZXB1YmxpY2FuIHBhcnR5IiwgeGF4dD0ibiIsCiAgICAgICAgICAgICBzaG93LmNsdXN0LmNlbnQ9RkFMU0UpCmBgYAoKIyBTdGVwIDM6IERhdGEgYW5hbHlzaXMKIyMgMy4zLiBUb3BpYyBtb2RlbGluZwoKCkZvciB0b3BpYyBtb2RlbGluZywgd2UgcHJlcGFyZSBhIGNvcnB1cyBvZiBzZW50ZW5jZSBzbmlwZXRzIGFzIGZvbGxvd3MuIEZvciBlYWNoIHNwZWVjaCwgd2Ugc3RhcnQgd2l0aCBzZW50ZW5jZXMgYW5kIHByZXBhcmUgYSBzbmlwZXQgd2l0aCBhIGdpdmVuIHNlbnRlbmNlIHdpdGggdGhlIGZsYW5raW5nIHNlbnRlbmNlcy4gCgpgYGB7cn0KY29ycHVzLmxpc3Q9c2VudGVuY2UubGlzdFsyOihucm93KHNlbnRlbmNlLmxpc3QpLTEpLCBdCnNlbnRlbmNlLnByZT1zZW50ZW5jZS5saXN0JHNlbnRlbmNlc1sxOihucm93KHNlbnRlbmNlLmxpc3QpLTIpXQpzZW50ZW5jZS5wb3N0PXNlbnRlbmNlLmxpc3Qkc2VudGVuY2VzWzM6KG5yb3coc2VudGVuY2UubGlzdCktMSldCmNvcnB1cy5saXN0JHNuaXBldHM9cGFzdGUoc2VudGVuY2UucHJlLCBjb3JwdXMubGlzdCRzZW50ZW5jZXMsIHNlbnRlbmNlLnBvc3QsIHNlcD0iICIpCnJtLnJvd3M9KDE6bnJvdyhjb3JwdXMubGlzdCkpW2NvcnB1cy5saXN0JHNlbnQuaWQ9PTFdCnJtLnJvd3M9YyhybS5yb3dzLCBybS5yb3dzLTEpCmNvcnB1cy5saXN0PWNvcnB1cy5saXN0Wy1ybS5yb3dzLCBdCmBgYAoKIyMjIFRleHQgbWluaW5nCmBgYHtyfQpkb2NzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UoY29ycHVzLmxpc3Qkc25pcGV0cykpCndyaXRlTGluZXMoYXMuY2hhcmFjdGVyKGRvY3NbW3NhbXBsZSgxOm5yb3coY29ycHVzLmxpc3QpLCAxKV1dKSkKYGBgCgojIyMjIFRleHQgYmFzaWMgcHJvY2Vzc2luZwoKYGBge3J9CiNyZW1vdmUgcG90ZW50aWFsbHkgcHJvYmxlbWF0aWMgc3ltYm9scwpkb2NzIDwtdG1fbWFwKGRvY3MsY29udGVudF90cmFuc2Zvcm1lcih0b2xvd2VyKSkKd3JpdGVMaW5lcyhhcy5jaGFyYWN0ZXIoZG9jc1tbc2FtcGxlKDE6bnJvdyhjb3JwdXMubGlzdCksIDEpXV0pKQoKI3JlbW92ZSBwdW5jdHVhdGlvbgpkb2NzIDwtIHRtX21hcChkb2NzLCByZW1vdmVQdW5jdHVhdGlvbikKd3JpdGVMaW5lcyhhcy5jaGFyYWN0ZXIoZG9jc1tbc2FtcGxlKDE6bnJvdyhjb3JwdXMubGlzdCksIDEpXV0pKQoKI1N0cmlwIGRpZ2l0cwpkb2NzIDwtIHRtX21hcChkb2NzLCByZW1vdmVOdW1iZXJzKQp3cml0ZUxpbmVzKGFzLmNoYXJhY3Rlcihkb2NzW1tzYW1wbGUoMTpucm93KGNvcnB1cy5saXN0KSwgMSldXSkpCgojcmVtb3ZlIHN0b3B3b3Jkcwpkb2NzIDwtIHRtX21hcChkb2NzLCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCJlbmdsaXNoIikpCndyaXRlTGluZXMoYXMuY2hhcmFjdGVyKGRvY3NbW3NhbXBsZSgxOm5yb3coY29ycHVzLmxpc3QpLCAxKV1dKSkKCiNyZW1vdmUgd2hpdGVzcGFjZQpkb2NzIDwtIHRtX21hcChkb2NzLCBzdHJpcFdoaXRlc3BhY2UpCndyaXRlTGluZXMoYXMuY2hhcmFjdGVyKGRvY3NbW3NhbXBsZSgxOm5yb3coY29ycHVzLmxpc3QpLCAxKV1dKSkKCiNTdGVtIGRvY3VtZW50CmRvY3MgPC0gdG1fbWFwKGRvY3Msc3RlbURvY3VtZW50KQp3cml0ZUxpbmVzKGFzLmNoYXJhY3Rlcihkb2NzW1tzYW1wbGUoMTpucm93KGNvcnB1cy5saXN0KSwgMSldXSkpCmBgYAoKIyMjIyBUb3BpYyBtb2RlbGluZwoKR2VuZ2VyYXRlIGRvY3VtZW50LXRlcm0gbWF0cmljZXMuIAoKYGBge3J9CmR0bSA8LSBEb2N1bWVudFRlcm1NYXRyaXgoZG9jcykKI2NvbnZlcnQgcm93bmFtZXMgdG8gZmlsZW5hbWVzI2NvbnZlcnQgcm93bmFtZXMgdG8gZmlsZW5hbWVzCnJvd25hbWVzKGR0bSkgPC0gcGFzdGUoY29ycHVzLmxpc3QkdHlwZSwgY29ycHVzLmxpc3QkRmlsZSwKICAgICAgICAgICAgICAgICAgICAgICBjb3JwdXMubGlzdCRUZXJtLCBjb3JwdXMubGlzdCRzZW50LmlkLCBzZXA9Il8iKQoKcm93VG90YWxzIDwtIGFwcGx5KGR0bSAsIDEsIHN1bSkgI0ZpbmQgdGhlIHN1bSBvZiB3b3JkcyBpbiBlYWNoIERvY3VtZW50CgpkdG0gIDwtIGR0bVtyb3dUb3RhbHM+IDAsIF0KY29ycHVzLmxpc3Q9Y29ycHVzLmxpc3Rbcm93VG90YWxzPjAsIF0KCmBgYAoKUnVuIExEQQoKYGBge3J9CiNTZXQgcGFyYW1ldGVycyBmb3IgR2liYnMgc2FtcGxpbmcKYnVybmluIDwtIDQwMDAKaXRlciA8LSAyMDAwCnRoaW4gPC0gNTAwCnNlZWQgPC1saXN0KDIwMDMsNSw2MywxMDAwMDEsNzY1KQpuc3RhcnQgPC0gNQpiZXN0IDwtIFRSVUUKCiNOdW1iZXIgb2YgdG9waWNzCmsgPC0gMTUKCiNSdW4gTERBIHVzaW5nIEdpYmJzIHNhbXBsaW5nCmxkYU91dCA8LUxEQShkdG0sIGssIG1ldGhvZD0iR2liYnMiLCBjb250cm9sPWxpc3QobnN0YXJ0PW5zdGFydCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWVkID0gc2VlZCwgYmVzdD1iZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVybmluID0gYnVybmluLCBpdGVyID0gaXRlciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGluPXRoaW4pKQojd3JpdGUgb3V0IHJlc3VsdHMKI2RvY3MgdG8gdG9waWNzCmxkYU91dC50b3BpY3MgPC0gYXMubWF0cml4KHRvcGljcyhsZGFPdXQpKQp0YWJsZShjKDE6aywgbGRhT3V0LnRvcGljcykpCndyaXRlLmNzdihsZGFPdXQudG9waWNzLGZpbGU9cGFzdGUoIi4vb3V0cHV0L0xEQUdpYmJzIixrLCJEb2NzVG9Ub3BpY3MuY3N2IikpCgojdG9wIDYgdGVybXMgaW4gZWFjaCB0b3BpYwpsZGFPdXQudGVybXMgPC0gYXMubWF0cml4KHRlcm1zKGxkYU91dCwyMCkpCndyaXRlLmNzdihsZGFPdXQudGVybXMsZmlsZT1wYXN0ZSgiLi9vdXRwdXQvTERBR2liYnMiLGssIlRvcGljc1RvVGVybXMuY3N2IikpCgojcHJvYmFiaWxpdGllcyBhc3NvY2lhdGVkIHdpdGggZWFjaCB0b3BpYyBhc3NpZ25tZW50CnRvcGljUHJvYmFiaWxpdGllcyA8LSBhcy5kYXRhLmZyYW1lKGxkYU91dEBnYW1tYSkKd3JpdGUuY3N2KHRvcGljUHJvYmFiaWxpdGllcyxmaWxlPXBhc3RlKCIuL291dHB1dC9MREFHaWJicyIsaywiVG9waWNQcm9iYWJpbGl0aWVzLmNzdiIpKQpgYGAKYGBge3J9CnRlcm1zLmJldGE9bGRhT3V0QGJldGEKdGVybXMuYmV0YT1zY2FsZSh0ZXJtcy5iZXRhKQp0b3BpY3MudGVybXM9TlVMTApmb3IoaSBpbiAxOmspewogIHRvcGljcy50ZXJtcz1yYmluZCh0b3BpY3MudGVybXMsIGxkYU91dEB0ZXJtc1tvcmRlcih0ZXJtcy5iZXRhW2ksXSwgZGVjcmVhc2luZyA9IFRSVUUpWzE6N11dKQp9CnRvcGljcy50ZXJtcwpsZGFPdXQudGVybXNbMSxdCmBgYApCYXNlZCBvbiB0aGUgbW9zdCBwb3B1bGFyIHRlcm1zIGFuZCB0aGUgbW9zdCBzYWxpZW50IHRlcm1zIGZvciBlYWNoIHRvcGljLCB3ZSBhc3NpZ24gYSBoYXNodGFnIHRvIGVhY2ggdG9waWMuIFRoaXMgcGFydCByZXF1aXJlIG1hbnVhbCBzZXR1cCBhcyB0aGUgdG9waWNzIGFyZSBsaWtlbHkgdG8gY2hhbmdlLiAKCmBgYHtyfQp0b3BpY3MuaGFzaD1jKCJGcmVlZG9tIiwgImdyZWF0IiwgIndpbGwiLCAid29yayIsICJzaGFsbCIsICJwZW9wbGUiLCAic3RhdGUiLCAidGltZSIsICJ3b3JsZCIsICJsYXciLCAid2FyIiwgInB1YmxpYyIsICJldmVyeSIsICJuYXRpb24iLCAiY2FuIikKY29ycHVzLmxpc3QkbGRhdG9waWM9YXMudmVjdG9yKGxkYU91dC50b3BpY3MpCmNvcnB1cy5saXN0JGxkYWhhc2g9dG9waWNzLmhhc2hbbGRhT3V0LnRvcGljc10KCmNvbG5hbWVzKHRvcGljUHJvYmFiaWxpdGllcyk9dG9waWNzLmhhc2gKY29ycHVzLmxpc3QuZGY9Y2JpbmQoY29ycHVzLmxpc3QsIHRvcGljUHJvYmFiaWxpdGllcykKb3JkZXJzID0gYXMuZmFjdG9yKGFzLm51bWVyaWMoY29ycHVzLmxpc3QuZGYkRmlsZU9yZGVyZWQpW25yb3coY29ycHVzLmxpc3QuZGYpOjFdKQpjb3JwdXMubGlzdC5kZjwtIGNiaW5kKGNvcnB1cy5saXN0LmRmLG9yZGVycykKYGBgCiMjIENsdXN0ZXJpbmcgb2YgdG9waWNzCmBgYHtyLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD00fQpwYXIobWFyPWMoMSwxLDEsMSkpCnRvcGljLnN1bW1hcnk9dGJsX2RmKGNvcnB1cy5saXN0LmRmKSU+JQogICAgICAgICAgICAgIHNlbGVjdChvcmRlcnMsIEZyZWVkb206Y2FuKSU+JQogICAgICAgICAgICAgIGdyb3VwX2J5KG9yZGVycyklPiUKICAgICAgICAgICAgICBzdW1tYXJpc2VfZWFjaChmdW5zKG1lYW4pKQp0b3BpYy5zdW1tYXJ5PWFzLmRhdGEuZnJhbWUodG9waWMuc3VtbWFyeSkKcm93bmFtZXModG9waWMuc3VtbWFyeSk9dG9waWMuc3VtbWFyeVssMV0KCnRvcGljLnBsb3Q9YygxLCAxMywgOSwgMTEsIDgsIDMsIDcpCnByaW50KHRvcGljcy5oYXNoW3RvcGljLnBsb3RdKQoKaGVhdG1hcC4yKGFzLm1hdHJpeCh0b3BpYy5zdW1tYXJ5Wyx0b3BpYy5wbG90KzFdKSwgCiAgICAgICAgICBzY2FsZSA9ICJjb2x1bW4iLCBrZXk9RiwgCiAgICAgICAgICBjb2wgPSBibHVlcmVkKDEwMCksCiAgICAgICAgICBjZXhSb3cgPSAwLjksIGNleENvbCA9IDAuOSwgbWFyZ2lucyA9IGMoOCwgMTQpLAogICAgICAgICAgdHJhY2UgPSAibm9uZSIsIGRlbnNpdHkuaW5mbyA9ICJub25lIikKCgpgYGAKCgoKI1N0ZXAgNCAtIEluc3BlY3QgYW4gb3ZlcmFsbCB3b3JkY2xvdWQKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTZ9CmR0bS50aWR5PXRpZHkoZHRtKQoKcHJpbnQoIkdlb3JnZVdhc2hpbmd0b24iKQpyYW5nID0gd2hpY2goc3Vic3RyKGR0bS50aWR5JGRvY3VtZW50LDIsbmNoYXIoZHRtLnRpZHkkZG9jdW1lbnQpLTQpPT0iR2VvcmdlV2FzaGluZ3RvbiIpCmR0bS50bXA9c3VtbWFyaXNlKGdyb3VwX2J5KGR0bS50aWR5W3JhbmcsXSwgdGVybSksIHN1bShjb3VudCkpCndvcmRjbG91ZChkdG0udG1wJHRlcm0sIGR0bS50bXAkYHN1bShjb3VudClgLAogICAgICAgICAgc2NhbGU9Yyg1LDAuNSksCiAgICAgICAgICBtYXgud29yZHM9MTAwLAogICAgICAgICAgbWluLmZyZXE9MSwKICAgICAgICAgIHJhbmRvbS5vcmRlcj1GQUxTRSwKICAgICAgICAgIHJvdC5wZXI9MC4zLAogICAgICAgICAgdXNlLnIubGF5b3V0PVQsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQoKcHJpbnQoIlRob21hc0plZmZlcnNvbiIpCnJhbmcgPSB3aGljaChzdWJzdHIoZHRtLnRpZHkkZG9jdW1lbnQsMixuY2hhcihkdG0udGlkeSRkb2N1bWVudCktNCk9PSJUaG9tYXNKZWZmZXJzb24iKQpkdG0udG1wPXN1bW1hcmlzZShncm91cF9ieShkdG0udGlkeVtyYW5nLF0sIHRlcm0pLCBzdW0oY291bnQpKQp3b3JkY2xvdWQoZHRtLnRtcCR0ZXJtLCBkdG0udG1wJGBzdW0oY291bnQpYCwKICAgICAgICAgIHNjYWxlPWMoNSwwLjUpLAogICAgICAgICAgbWF4LndvcmRzPTEwMCwKICAgICAgICAgIG1pbi5mcmVxPTEsCiAgICAgICAgICByYW5kb20ub3JkZXI9RkFMU0UsCiAgICAgICAgICByb3QucGVyPTAuMywKICAgICAgICAgIHVzZS5yLmxheW91dD1ULAogICAgICAgICAgcmFuZG9tLmNvbG9yPUZBTFNFLAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOSwiQmx1ZXMiKSkKCnByaW50KCJBYnJhaGFtTGluY29sbiIpCnJhbmcgPSB3aGljaChzdWJzdHIoZHRtLnRpZHkkZG9jdW1lbnQsMixuY2hhcihkdG0udGlkeSRkb2N1bWVudCktNCk9PSJBYnJhaGFtTGluY29sbiIpCmR0bS50bXA9c3VtbWFyaXNlKGdyb3VwX2J5KGR0bS50aWR5W3JhbmcsXSwgdGVybSksIHN1bShjb3VudCkpCndvcmRjbG91ZChkdG0udG1wJHRlcm0sIGR0bS50bXAkYHN1bShjb3VudClgLAogICAgICAgICAgc2NhbGU9Yyg1LDAuNSksCiAgICAgICAgICBtYXgud29yZHM9MTAwLAogICAgICAgICAgbWluLmZyZXE9MSwKICAgICAgICAgIHJhbmRvbS5vcmRlcj1GQUxTRSwKICAgICAgICAgIHJvdC5wZXI9MC4zLAogICAgICAgICAgdXNlLnIubGF5b3V0PVQsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQoKcHJpbnQoIkZyYW5rbGluRFJvb3NldmVsdCIpCnJhbmcgPSB3aGljaChzdWJzdHIoZHRtLnRpZHkkZG9jdW1lbnQsMixuY2hhcihkdG0udGlkeSRkb2N1bWVudCktNCk9PSJGcmFua2xpbkRSb29zZXZlbHQiKQpkdG0udG1wPXN1bW1hcmlzZShncm91cF9ieShkdG0udGlkeVtyYW5nLF0sIHRlcm0pLCBzdW0oY291bnQpKQp3b3JkY2xvdWQoZHRtLnRtcCR0ZXJtLCBkdG0udG1wJGBzdW0oY291bnQpYCwKICAgICAgICAgIHNjYWxlPWMoNSwwLjUpLAogICAgICAgICAgbWF4LndvcmRzPTEwMCwKICAgICAgICAgIG1pbi5mcmVxPTEsCiAgICAgICAgICByYW5kb20ub3JkZXI9RkFMU0UsCiAgICAgICAgICByb3QucGVyPTAuMywKICAgICAgICAgIHVzZS5yLmxheW91dD1ULAogICAgICAgICAgcmFuZG9tLmNvbG9yPUZBTFNFLAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOSwiQmx1ZXMiKSkKCnByaW50KCJCYXJhY2tPYmFtYSIpCnJhbmcgPSB3aGljaChzdWJzdHIoZHRtLnRpZHkkZG9jdW1lbnQsMixuY2hhcihkdG0udGlkeSRkb2N1bWVudCktNCk9PSJCYXJhY2tPYmFtYSIpCmR0bS50bXA9c3VtbWFyaXNlKGdyb3VwX2J5KGR0bS50aWR5W3JhbmcsXSwgdGVybSksIHN1bShjb3VudCkpCndvcmRjbG91ZChkdG0udG1wJHRlcm0sIGR0bS50bXAkYHN1bShjb3VudClgLAogICAgICAgICAgc2NhbGU9Yyg1LDAuNSksCiAgICAgICAgICBtYXgud29yZHM9MTAwLAogICAgICAgICAgbWluLmZyZXE9MSwKICAgICAgICAgIHJhbmRvbS5vcmRlcj1GQUxTRSwKICAgICAgICAgIHJvdC5wZXI9MC4zLAogICAgICAgICAgdXNlLnIubGF5b3V0PVQsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQoKcHJpbnQoIkRvbmFsZEpUcnVtcCIpCnJhbmcgPSB3aGljaChzdWJzdHIoZHRtLnRpZHkkZG9jdW1lbnQsMixuY2hhcihkdG0udGlkeSRkb2N1bWVudCktNCk9PSJEb25hbGRKVHJ1bXAiKQpkdG0udG1wPXN1bW1hcmlzZShncm91cF9ieShkdG0udGlkeVtyYW5nLF0sIHRlcm0pLCBzdW0oY291bnQpKQp3b3JkY2xvdWQoZHRtLnRtcCR0ZXJtLCBkdG0udG1wJGBzdW0oY291bnQpYCwKICAgICAgICAgIHNjYWxlPWMoNSwwLjUpLAogICAgICAgICAgbWF4LndvcmRzPTEwMCwKICAgICAgICAgIG1pbi5mcmVxPTEsCiAgICAgICAgICByYW5kb20ub3JkZXI9RkFMU0UsCiAgICAgICAgICByb3QucGVyPTAuMywKICAgICAgICAgIHVzZS5yLmxheW91dD1ULAogICAgICAgICAgcmFuZG9tLmNvbG9yPUZBTFNFLAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOSwiQmx1ZXMiKSkKCgpgYGAKCiMgTXkgc3RvcnkKCldlIGhhdmUgYW5hbHl6ZWQgdGhlIDU4IGluYXVndXJhbCBzcGVlY2hlcyBvZiBwcmVzaWRlbnRzLiBBbmQgSSBoYXZlIGZvdW5kIHNvbWUgaW50ZXJlc3RpbmcgdGhpbmdzIGJlaGluZCB0aGVpciBzcGVlY2hlcy4KClRvIHN0YXJ0IHdpdGgsIGFzIHRoZSBmYXRoZXIgb2YgQW1lcmljYSwgR2VvcmdlIFdhc2hpbmd0b24gaXMgYSB2ZXJ5IHNwZWNpYWwgcHJlc2lkZW50LiBOb3Qgb25seSBiZWNhdXNlIGhpcyBncmVhdCBjb250cmlidXRpb24gdG8gQW1lcmljYSwgYnV0IGFsc28gaGlzIHN0eWxlIG9mIGdpdmluZyBzcGVlY2hlcy4gQW1vbmcgYWxsIHRoZXNlIDQwIHByZXNpZGVudHMgaW4gb3VyIHN0dWR5LCBHZW9yZ2UgV2FzaGluZ3RvbiBpcyB0aGUgbW9zdCBsaWtlbHkgdG8gc2F5IGxvbmcgc2VudGVuY2VzLiBJbiBoaXMgaW5hdWd1cmFsIHNwZWVjaCwgdGhlcmUgYXJlIG9ubHkgdHdvIHNlbnRlbmNlcyB0aGF0IGhhdmUgbGVzcyB0aGFuIDEwIHdvcmRzLCB3aGljaCBhcmUgImJldHdlZW4gZHV0eSBhbmQgYWR2YW50YWdlIiBhbmQgIkZyb20gdGhpcyByZXNvbHV0aW9uIEkgaGF2ZSBpbiBubyBpbnN0YW5jZSBkZXBhcnRlZCIuIFdlIGNvdWxkIGJlbGlldmUgdGhhdCBhZnRlciBsaXN0ZW4gdG8gdGhlIHJlY29yZCBvZiBHZW9yZ2UgV2FzaGluZ3RvbidzIGluYXVndXJhbCBzcGVlY2gsIHRoZSBsYXR0ZXIgcHJlc2lkZW50cyBhbHNvIGZvdW5kIGhpcyBzZW50ZW5jZSBzb3VuZHMgYSBiaXQgbG9uZyBzbyB0aGV5IHRlbmQgdG8gc2hvcnQgdGhlaXIgc2VudGVuY2VzIHdoZW4gZ2l2aW5nIHNwZWVjaGVzLiBTbyBpdCBiZWNvbWVzIGEgdHJlbmQgdGhhdCBhcyB0aW1lIGdvZXMgYnksIHByZXNpZGVudHMgdGVuZCB0byB1c2Ugc2hvcnRlciBzZW50ZW5jZXMgYW5kIGxlc3Mgd29yZHMgaW4gdGhlaXIgaW5hdWd1cmFsIHNwZWVjaC4gQXMgd2UgY2FuIHNlZSwgc2hvcnRlciBzZW50ZW5jZXMgYW5kIGxlc3Mgd29yZHMgbWFrZSBhIHNwZWVjaCBtb3JlIHByZWNpc2UgYW5kIGVhenkgZm9yIGF1ZGllbmNlcy4gQW5kIHNob3J0IHdvcmRzIGFuZCBzZW50ZW5jZXMgYXJlIG1vcmUgbGlrZWx5IHRvIGNhdXNlIGVtb3Rpb25hbCByZXNvbmFuY2UsIHdoaWNoIG1heSBoZWxwIHRoZW0gd2lucyB0aGUgdHJ1c3Qgb2YgcGVvcGxlLgoKSG93ZXZlciwgR2VvcmdlIFdhc2hpbmd0b24gYW5kIFRob21hcyBKZWZmZXJzb24gbGl2ZWQgaW4gdGhlIHNhbWUgcGVyaW9kIGJ1dCB0aGV5IHNob3dlZCBxdWl0ZSBkaWZmZXJlbnQgd2F5cyBvZiBnaXZpbmcgc3BlZWNoLiBVbmxpa2UgR2VvcmdlIFdhc2hpbmd0b24sIFRob21hcyBKZWZmZXJzb24gdXNlcyBzaG9ydGVyIHNlbnRlbmNlcyBjb21wYXJlZCB0byB0aGUgcHJlc2lkZW50cyBpbiBoaXMgbmVhciBmdXJ0dXJlLiBMZXQncyByZWNhbGwgZnJvbSB0aGVpciB0ZWVuYWdlciBlbnZpcm9ubWVudC4gR2VvcmdlIFdhc2hpbmd0b24gbGl2ZWQgaW4gdGhlIGNvdW50cnlzaWRlIGFuZCBoYWQgbmV2ZXIgZ290IGVkdWNhdGlvbiB1bnRpbCAxNSB5ZWFycyBvbGQuIFRoZW4gaGUgbGVhcm5lZCBmcm9tIHRoZSBsb2NhbCB0dXRvciBhbmQgc2hvd2VkIHRhbGVudCBpbiBtYXRoLCBnZW9tZXRyeSBhbmQgbWVhc3VyZW1lbnQuIFdlIG1heSBjb25zaWRlciB0aGlzIGFzIGFuIGV4cGxhaW5hdGlvbiBvZiBHZW9yZ2UgV2FzaGluZ3RvbidzIGluYXVndXJhbCBzcGVlY2ggdGhhdCBoZSBpcyBnb29kIGF0IHNvbHZpbmcgY29tcGxpY2F0ZWQgcHJvYmxlbXMgYW5kIGNhbiBlYXNpbHkgdW5kZXJ0YW5kIGxvbmcgc2VudGVuY2VzLiBBcyBmb3IgVGhvbWFzIEplZmZlcnNvbiwgaGUgcmVjaWV2ZWQgY2xhc3NpY2FsIGVkdWNhdGlvbiBhbmQgbGVhcm5lZCBoaXN0b3J5IGFuZCBwb2xpdGljcywgd2hpY2ggbWF5IG1hZGUgaGltIGEgZ29vZCBzcGVha2VyIGF0IGhpcyBwZXJpb2QuIEFuZCBmb3Igbm93IGl0IGFsbW9zdCBiZWNvbWVzIGEgdHJlbmQgdGhhdCB0aGUgaW5hdWd1cmFsIHNwZWVjaCB1c2VzIHNob3J0IHNlbnRlbmNlcy4gTWF5YmUgaXQgaXMgYmVjYXVzZSBtb2Rlcm4gcGVvcGxlIGFyZSB0b28gdGlyZWQgdG8gbGlzdGVuIHRvIGxvbmcgc2VudGVuY2VzLgogCkFub3RoZXIgaW50ZXJlc3RpbmcgZGlzY292ZXIgaXMgdGhhdCBwcmVzaWRlbnRzJyB3b3JkcyBhbHdheXMgcmVmbGVjdCB0aGVpciB0aW1lIGFnZSBhbmQgcGVvcGxlJ3MgaG9wZS4gRm9yIHRoZSBmaXJzdCB0d28gcHJlc2lkZW50cywgd2UgY2FuIHNlZSBmcm9tIHRoZSB3b3JkIGNsb3VkIHRoYXQgdGhleSBmb2N1c2VkIG1vcmUgb24gZXF1YWxpdHkgb2YgZXZlcnkgcGVvcGxlLiBUaGV5IGxpdmVkIGluIGEgcGVyaW9kIHRoYXQgQW1lcmljYSB3YXMganVzdCBmb3VuZGVkLiBJdCBiZWNhbWUgdmVyeSBpbXBvcnRhbnQgdGhhdCBldmVyeSBpbmRpdmlkdWFsJ3MgcmlnaHQgd2FzIHRyZWF0ZWQgZXF1YWxseS4gV2hpbGUgd2hlbiBpdCBjYW1lIHRvIHRoZSB0aW1lIG9mIEFicmFoYW0gTGluY29sbiB3aG8gbGVhZCB0aGUgY2l2aWwgd2FyIGFuZCBGcmFua2xpbiBELiBSb29zZXZlbHQgd2hvIGpvaW5lZCB0aGUgc2Vjb25kIHdvcmxkIHdhci4gVGhlaXIgc3BlZWNoZXMgd2VyZSBzdHJvbmdseSByZWxhdGVkIHRvIHRoZSB0b3BpYyBvZiB3YXIuIFdlIGNhbiBmaW5kIHdvcmRzIGFib3V0IHVuaW9uIG9yIHN0YXRlcyBpbiBBYnJhaGFtIExpbmNvbG4ncyBzcGVlY2ggd2hpbGUgcGVhY2UgaW4gRnJhbmtsaW4gRC4gUm9vc2V2ZWx0J3Mgc3BlZWNoZXMuIE5vdyBsZXQncyB0aGluayBhYm91dCBCYXJhY2sgT2JhbWEgYW5kIERvbmFsZCBUcnVtcC4gVGhleSBib3RoIGhhdmUgdGhlIHdpbGxpbmcgdG8gcmVjb3ZlciBmcm9tIDIwMDggZWNvbm9taWMgY3Jpc2lzLCBzbyB0aGV5IHRhbGtlZCBtb3JlIGFib3V0IHBhc3QsIHRvZ2V0aGVyIGFuZCBBbWVyaWNhLCB3aGljaCBlbmNvdXJhZ2VkIHBlb3BsZSB0byBmaWdodCBmb3IgdGhlIGhhcmQgZGF5cyB0b2dldGhlci4KCkxhc3QgYnV0IG5vdCBsZWFzdCwgZnJvbSB0aGUgY2x1c3RlcmluZyBvZiBlbW90aW9ucywgd2UgYWxzbyBmb3VuZCB0aGF0IHRoZSBwb3NpdGl2ZSBlbW90aW9ucyBpcyB0aGUgbW9zdCB1c2VkIGZlZWxpbmcgaW4gaW5hdWd1cmFsIHNwZWVjaC4gSXQgaXMgbm90IGhhcmQgdG8gZXhwbGFpbiB0aGF0IG9ubHkgaWYgdGhlIHNwZWFrZXIgc2hvd2VzIHRydXN0ZnVsIHF1YWxpdHkgdG8gYXVkaWVuY2VzLCB0aGUgYXVkaWVuY2VzIHdpbGwgdHJ1c3QgeW91IGFzIGEgZ29vZCBwcmVzaWRlbnQuIFdoYXQncyBtb3JlLCB3ZSBhbHNvIGNhbiBzZWUgc29tZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBlbW90aW9uIGNsdXN0ZXJpbmcgYW5kIHBhcnR5IGxhYmVscy4gVGhlIG9uZXMgc2hhcmUgdGhlIHNhbWUgaWRlYSB3aWxsIHNob3cgc21pbGFyIGVtb3Rpb25zIHdoZW4gZ2l2aW5nIHNwZWVjaGVzLgoKTGV0J3MgdXNlIHRoZSBtb3N0IGVtb3Rpb24gdXNlZCBpbiBpbmF1Z3VyYWwgc3BlZWNoIHRvIGVuZCBvdXIgc3R1ZHksIHRydXN0IHBlb3BsZSwgcGVvcGxlIHRydXN0IHlvdS4=